/* 
 * Copyright (C) 2013, 2014 lex xiang
 *
 * file:	drivers/tty.h
 * history:	2013 Juy 11 created by lex
 */
#ifndef __TTY_H__
#define __TTY_H__

#include "types.h"

#define NR_ASCII_CODE	128

#define CH_NUL		0	/* ^@ \0 Null char		  */
#define CH_SOH		1	/* ^A    Start of Heading         */
#define CH_STX		2	/* ^B    Start of Text		  */
#define CH_ETX		3	/* ^C    End of Text		  */
#define CH_EOT		4	/* ^D    End of Transmission	  */
#define CH_ENQ		5	/* ^E    Enquiry		  */
#define CH_ACK		6	/* ^F    Acknowledgment		  */
#define CH_BEL		7	/* ^G \a Bell			  */
#define CH_BS 		8	/* ^H \b Back Space		  */
#define CH_HT 		9	/* ^I \t Horizontal Tab		  */
#define CH_LF 		10	/* ^J \n Line Feed		  */
#define CH_VT 		11	/* ^K \v Vertical Tab		  */
#define CH_FF 		12	/* ^L \f Form Feed		  */
#define CH_CR 		13	/* ^M \r Carriage Return	  */
#define CH_SO 		14	/* ^N    Shift Out / X-On	  */
#define CH_SI 		15	/* ^O    Shift In / X-Off	  */
#define CH_DLE		16	/* ^P    Data Line Escape	  */
#define CH_DC1		17	/* ^Q    Device Control 1	  */
#define CH_DC2		18	/* ^R    Device Control 2	  */
#define CH_DC3		19	/* ^S    Device Control 3	  */
#define CH_DC4		20	/* ^T    Device Control 4	  */
#define CH_NAK		21	/* ^U    Negative Acknowledgement */
#define CH_SYN		22	/* ^V    Synchronous Idle	  */
#define CH_ETB		23	/* ^W    End of Transmit Block    */
#define CH_CAN		24	/* ^X    Cancel			  */
#define CH_EM 		25	/* ^Y    End of Medium		  */
#define CH_SUB		26	/* ^Z    Substitute		  */
#define CH_ESC		27	/* ^[ \e Escape			  */
#define CH_FS 		28	/* ^\    File Separator		  */
#define CH_GS 		29	/* ^]    Group Separator	  */
#define CH_RS 		30	/* ^^    Record Separator	  */
#define CH_US 		31	/* ^_    Unit Separator           */
#define CH_DEL		127	/* ^?    Delete			  */

#define HOOK_HT		0
#define HOOK_DLE	1
#define HOOK_SO		2
#define	HOOK_RSV	3
#define NR_HOOK_MAX	(HOOK_RSV + 1)


#define console_clear(tty)	(tty)->op.dev_printf(tty, "\033[2J")
#define cursor_end_clear(tty)	(tty)->op.dev_printf(tty, "\033[J")
#define cursor_up(tty, n)	(tty)->op.dev_printf(tty, "\033[%dA", (n))
#define cursor_down(tty, n)	(tty)->op.dev_printf(tty, "\033[%dB", (n))
#define cursor_forward(tty, n)	(tty)->op.dev_printf(tty, "\033[%dC", (n))
#define cursor_backward(tty, n)	(tty)->op.dev_printf(tty, "\033[%dD", (n))
#define cursor_reset(tty)	(tty)->op.dev_printf(tty, "\033[3H")
#define cursor_hide(tty)	(tty)->op.dev_printf(tty, "\033[?25l")
#define cursor_show(tty)	(tty)->op.dev_printf(tty, "\033[?25h")
#define cursor_highlight(tty)	(tty)->op.dev_printf(tty, "\033[7m")
#define cursor_unhighlight(tty)	(tty)->op.dev_printf(tty, "\033[27m")
#define cursor_kill_line(tty)	(tty)->op.dev_printf(tty, "\033[K")
#define cursor_erase(tty, n)	(tty)->op.dev_printf(tty, "\033[%dP", (n))
#define cursor_save(tty)	(tty)->op.dev_printf(tty, "\033[s")
#define cursor_undo(tty)	(tty)->op.dev_printf(tty, "\033[u")

struct tty;
typedef u8		(*fp_tty_getc)(struct tty *);
typedef void		(*fp_tty_putc)(struct tty *, u8);
typedef void		(*fp_tty_puts)(struct tty *, u8 *);
typedef s32		(*fp_tty_ch_handler)(struct tty *, u8);
typedef void		(*fp_tty_printf)(struct tty *, char *, ...);
typedef void		(*fp_tty_misc)(void *);
typedef s32		(*fp_tty_insert_str)(struct tty *, u8 *);

#define TTY_COL_MAX	80

struct tty {
	struct tty *next;

	int	uart_port;

	struct {
		fp_tty_putc		putc;
		fp_tty_getc		getc;
		fp_tty_puts		puts;
		fp_tty_printf		dev_printf;
		fp_tty_insert_str	insert_str;
		void			(*redisplay)(struct tty *);
		s32			(*get_line)(struct tty *, u8 *, s32);
		s32			(*read_line)(struct tty *, u8 *, s32);
		void			(*save_pos)(struct tty *, u8 *str);
		void			(*drain)(struct tty *);

		fp_tty_ch_handler	ch_handler[NR_ASCII_CODE];

		fp_tty_misc		hook[4];
		void			*hook_arg;
	} op;

	u8 done;
	u8 mode;
	u8 modified;

#define TTY_BUF_MAX	512

	u8	line[TTY_BUF_MAX];
	u32	cursor;
	u32	prev;
	u32	end;
	u32	beg;			/* begin of command 
					 * generally speaking, it used for 
					 * save the prompt len
					 */

	u8	killed[TTY_BUF_MAX];
	u32	killed_sz;
} ;

extern struct tty * tty_alloc();
extern void tty_free(struct tty *tty);
extern s32 tty_get_line(struct tty *tty, u8 *buf, s32 size);
extern u8 tty_get_char(struct tty * tty);
extern void tty_put_char(struct tty * tty, u8 ch);
extern void tty_put_string(struct tty *tty, char *string);
extern void tty_printf(struct tty *tty, char *fmt, ...);
extern s32 tty_init(struct tty *tty, 
			int uart_port, 
			fp_tty_getc getc, 
			fp_tty_putc putc, 
			fp_tty_puts puts,
			fp_tty_printf printf);


#endif	/* end of __TTY_H__ */
